import traceback
from multiprocessing.pool import ThreadPool

from com.stock.mainStock.stockList import stock_list
from com.stock.stockKline import XueQiuCookie
from com.util.assertUtil import newRound
from com.util.httpRequest import HttpRequest
from com.util.loggingUtil import Logs
from com.util.pushUtil import pushDingDing
from com.util.tcp.tcpService import TcpService

Log = Logs()


def getXueQiuData(code, marketType):
    """
    通过雪球获取前复权数据
    :param code:  股票
    :param marketType:市场类型
    :param limit: 获取条数
    :return:
    """
    marketDict = {1: "SH", 2: "SZ", 18: "BJ"}
    codeStr = f"{marketDict.get(int(marketType))}{code}"
    get_url = "https://stock.xueqiu.com/v5/stock/quote.json?" \
              "symbol=" + codeStr + "&extend=detail"
    cookie_headers = {
        'Cookie': XueQiuCookie,
        'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.84 Safari/537.36'
    }
    resData = HttpRequest().http_request(method='GET', url=get_url, headers=cookie_headers)
    return resData


def newFloat(data):
    if data:
        return newRound(data, 2)
    else:
        return 0.00


class XueQiuStockBaseInfo(object):
    """
    雪球个股盘口数据
    """

    def __init__(self, code, marketType):
        res = getXueQiuData(code, marketType)
        self.parse(res['data']['quote'], res['data']['others'])

    def parse(self, quote, others):
        if quote and others:
            # 最高
            self.high = newFloat(quote.get('high'))
            # 最低
            self.low = newFloat(quote.get('low'))
            # 今开
            self.open = newFloat(quote.get('open'))
            # 昨收
            self.last_close = newFloat(quote.get('last_close'))
            # 当前
            self.current = newFloat(quote.get('current'))
            # 涨停
            self.limit_up = newFloat(quote.get('limit_up'))
            # 跌停
            self.limit_down = newFloat(quote.get('limit_down'))
            # 成交量 #手
            self.tradeAmount = newFloat(quote.get('volume')) / 100
            # 成交额
            self.tradeVal = newFloat(quote.get('amount'))
            # 量比
            self.amountRate = newFloat(quote.get('volume_ratio'))
            # 委比
            self.entrustRate = newFloat(others.get('pankou_ratio'))
            # 换手率
            self.exchangeRatio = newFloat(quote.get('turnover_rate'))
            # 振幅
            self.amplitude = newFloat(quote.get('amplitude'))
            # 市盈率（动）
            self.dynPERate = newFloat(quote.get('pe_forecast'))
            # 市盈率（静）
            self.peRate = newFloat(quote.get('pe_lyr'))
            # 市盈率（TTM）
            self.peTTM = newFloat(quote.get('pe_ttm'))
            # 市净率
            self.pb = newFloat(quote.get('pb'))
            # 每股收益
            self.eps = newFloat(quote.get('eps'))
            # 每股净资产
            self.navps = newFloat(quote.get('navps'))
            # 52周最高
            self.high52w = newFloat(quote.get('high52w'))
            # 股息(TTM)
            self.dividend = newFloat(quote.get('dividend'))
            # 股息率(TTM) %
            self.dividend_yield = newFloat(quote.get('dividend_yield'))
            # 52周最低
            self.low52w = newFloat(quote.get('low52w'))
            # 总股本
            self.total_shares = newFloat(quote.get('total_shares'))
            # 流通股
            self.float_shares = newFloat(quote.get('float_shares'))
            # 货币单位
            self.currency = quote.get('currency')
            # 总市值
            self.totalVal = newFloat(quote.get('market_capital'))
            # 流通值
            self.flowTotalVal = newFloat(quote.get('float_market_capital'))


class WogooStockBaseInfo(object):
    """
    市值风云盘口数据
    """

    def __init__(self, code, marketType):
        res = TcpService().getStockBaseInfos(code, marketType)
        if res:
            self.parse(res)
        else:
            Log.error(f"code{code}，获取wogoo数据失败")

    def parse(self, data):
        # 最高
        self.high = self.getWogooFloat(data.get('highestPrice'), True)
        # 最低
        self.low = self.getWogooFloat(data.get('lowestPrice'), True)
        # 今开
        self.open = self.getWogooFloat(data.get('openPrice'), True)
        # 昨收
        self.last_close = self.getWogooFloat(data.get('yesterdayClosePrice'), True)
        # 今收
        self.close = self.getWogooFloat(data.get('closePrice'), True)
        # 成交量 #手
        self.tradeAmount = newFloat(data.get('tradeAmount')) / 100
        # 成交额
        self.tradeVal = self.getWogooFloat(data.get('tradeVal'))
        # 换手率
        self.exchangeRatio = self.getWogooFloat(data.get('exchangeRatio'))
        # 当前展示
        self.current = self.getWogooFloat(data.get('currDisplayPrice'), True)
        # 总市值
        self.totalVal = self.getWogooFloat(data.get('totalVal'))
        # 流通市值
        self.flowTotalVal = self.getWogooFloat(data.get('flowTotalVal'))
        # 振幅 例如2.8%  值为0.0280
        self.amplitude = self.getWogooFloat(data.get('amplitude'))
        # 量比
        self.amountRate = self.getWogooFloat(data.get('amountRate'))
        # 委比
        self.entrustRate = self.getWogooFloat(data.get('entrustRate'))
        # 均价
        self.avgPrice = self.getWogooFloat(data.get('avgPrice'))
        # 市净率
        self.pb = self.getWogooFloat(data.get('pbRate'))
        # 市盈率（TTM）
        self.peTTM = self.getWogooFloat(data.get('peTTM'))
        # 市盈率（静）
        self.peRate = self.getWogooFloat(data.get('peRate'))
        # 市盈率（动）
        self.dynPERate = self.getWogooFloat(data.get('dynPERate'))

    def getWogooFloat(self, data, is_2f=False):
        # 不存在
        if not data:
            return 0.0
        # is_2f=False 处理指数399【399001】，000【000852】等返回.后4位数字处理
        val = newFloat(data.get('value')) / (10 ** newFloat(data.get('decimal')))
        if is_2f:
            return newRound(val, 2)
        else:
            return val


def compare(xq=dict, wg=dict, code=str):
    failDict = {}

    for name in wg:
        # 雪球数据中存在字段
        if xq.__contains__(name):
            # 过滤委比，量比
            if name in ['entrustRate', 'amountRate']:
                continue

            if name in ['pb', 'peTTM', 'peRate', 'dynPERate', 'amountRate']:
                if not compareFloat(xq[name], wg[name]):
                    failDict.setdefault(name, f"{xq[name]}!={wg[name]}")
                    Log.error(f"{name},{xq[name]}!={wg[name]}")

            elif name in ['totalVal', 'flowTotalVal', 'tradeVal']:
                if not compareFloat(xq[name], wg[name]):
                    failDict.setdefault(name, f"{xq[name]}!={wg[name]}")
                    Log.error(f"{name},{xq[name]}!={wg[name]}")

            elif name in ['amplitude', 'entrustRate', 'exchangeRatio']:
                wgValue = wg[name] * 100
                if not compareFloat(xq[name], wgValue):
                    failDict.setdefault(name, f"{xq[name]}!={wg[name]}")
                    Log.error(f"{name},{xq[name]}!={wgValue}")

            else:  # 其余字段比较
                if xq[name] != wg[name]:
                    failDict.setdefault(name, f"{xq[name]}!={wg[name]}")
                    Log.error(f"{name},{xq[name]}!={wg[name]}")

    if failDict.__len__() > 0:
        failMap.setdefault(code, failDict)


failMap = {}


def compareFloat(a=float, b=float, RoundPercent=2 * 0.05):
    # 排除一些退市数据，不记录
    if a == 0.0 or b == 0.0:
        return True

    # 防止为0 新股就为0, 2*percent,percent即差值大致占比
    try:
        return abs(a - b) / abs(a + b) <= RoundPercent
    except ZeroDivisionError:
        return True


def threadCompare(codeStr):
    datas = str(codeStr).split(".")
    code = str(datas[0])
    marketType = int(datas[1])

    if code.startswith('1') or code.startswith('5'):
        return
    Log.info(f"开始校验{codeStr}")
    try:
        # 雪球数据
        xueQiuBaseInfo = XueQiuStockBaseInfo(code, marketType)
        xq_dict = vars(xueQiuBaseInfo)

        # 吾股数据
        wogooBaseInfo = WogooStockBaseInfo(code, marketType)
        wg_dict = vars(wogooBaseInfo)
        Log.info(f'结束校验{codeStr},\nxueqiu：{xq_dict}\nwogoo{wg_dict}')
        if xq_dict and wg_dict:
            compare(xq_dict, wg_dict, code)
    except:
        Log.error(f"code:[{codeStr}],Error{traceback.format_exc()}")


def run():
    # 对比前复权
    codeList = stock_list
    #codeList = codeList[0:200]
    pool = ThreadPool(5)
    pool.map(threadCompare, codeList)
    pool.close()  # 关闭进程池，不再接受新的进程
    pool.join()  # 主进程阻塞等待子进程的退出

    Log.info(f"股股票基本面指标对比结果xq:wg------:"
             f"{failMap}")
    result = f"股票基本面指标对比结果,总数{codeList.__len__()},错误数:{failMap.__len__()},具体查看日志"
    pushDingDing(result)
    Log.info(f"--------结束-------")
    # 关闭tcp池
    TcpService().close()


if __name__ == '__main__':
    run()
